"""JWT authentication handler."""

from typing import Dict, Any, Optional
from datetime import datetime, timedelta
import os
import logging

import jwt
from fastapi import HTTPException, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

logger = logging.getLogger(__name__)

# Security configuration
SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-secret-key-change-in-production")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "1440"))  # 24 hours

security = HTTPBearer()


def create_access_token(
    data: Dict[str, Any],
    expires_delta: Optional[timedelta] = None
) -> str:
    """Create a JWT access token.
    
    Args:
        data: Data to encode in the token
        expires_delta: Optional custom expiration time
        
    Returns:
        Encoded JWT token
    """
    to_encode = data.copy()
    
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    to_encode.update({"exp": expire})
    
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def verify_token(token: str) -> Dict[str, Any]:
    """Verify and decode a JWT token.
    
    Args:
        token: JWT token to verify
        
    Returns:
        Decoded token payload
        
    Raises:
        HTTPException: If token is invalid or expired
    """
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=401,
            detail="Token has expired",
            headers={"WWW-Authenticate": "Bearer"}
        )
    except jwt.JWTError as e:
        logger.error(f"JWT verification error: {e}")
        raise HTTPException(
            status_code=401,
            detail="Could not validate credentials",
            headers={"WWW-Authenticate": "Bearer"}
        )


async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Security(security)
) -> Dict[str, Any]:
    """Get the current authenticated user from JWT token.
    
    Args:
        credentials: HTTP Bearer credentials
        
    Returns:
        User information from token
        
    Raises:
        HTTPException: If authentication fails
    """
    token = credentials.credentials
    
    try:
        payload = verify_token(token)
        
        # Extract user information
        user_id = payload.get("sub")  # Subject (user ID)
        if user_id is None:
            raise HTTPException(
                status_code=401,
                detail="Invalid authentication credentials",
                headers={"WWW-Authenticate": "Bearer"}
            )
        
        # Return user information
        return {
            "user_id": user_id,
            "email": payload.get("email"),
            "username": payload.get("username"),
            "roles": payload.get("roles", []),
            "permissions": payload.get("permissions", [])
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Authentication error: {e}")
        raise HTTPException(
            status_code=401,
            detail="Could not validate credentials",
            headers={"WWW-Authenticate": "Bearer"}
        )


async def get_current_active_user(
    current_user: Dict[str, Any] = Security(get_current_user)
) -> Dict[str, Any]:
    """Get current active user.
    
    This can be extended to check if user is active in database.
    
    Args:
        current_user: Current user from JWT
        
    Returns:
        Active user information
        
    Raises:
        HTTPException: If user is not active
    """
    # Here you could add additional checks like:
    # - Check if user exists in database
    # - Check if user account is active
    # - Check if user has required permissions
    
    # For now, just return the user
    return current_user


def create_refresh_token(
    data: Dict[str, Any],
    expires_delta: Optional[timedelta] = None
) -> str:
    """Create a refresh token.
    
    Args:
        data: Data to encode in the token
        expires_delta: Optional custom expiration time
        
    Returns:
        Encoded refresh token
    """
    to_encode = data.copy()
    
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(days=30)  # 30 days for refresh token
    
    to_encode.update({
        "exp": expire,
        "type": "refresh"
    })
    
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt


def verify_refresh_token(token: str) -> Dict[str, Any]:
    """Verify a refresh token.
    
    Args:
        token: Refresh token to verify
        
    Returns:
        Decoded token payload
        
    Raises:
        HTTPException: If token is invalid
    """
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        
        # Verify it's a refresh token
        if payload.get("type") != "refresh":
            raise HTTPException(
                status_code=401,
                detail="Invalid token type"
            )
        
        return payload
        
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=401,
            detail="Refresh token has expired"
        )
    except jwt.JWTError:
        raise HTTPException(
            status_code=401,
            detail="Invalid refresh token"
        )


# Optional: Role-based access control decorators

def require_role(required_roles: list[str]):
    """Decorator to require specific roles.
    
    Args:
        required_roles: List of required roles
        
    Returns:
        Dependency function
    """
    async def role_checker(
        current_user: Dict[str, Any] = Security(get_current_user)
    ) -> Dict[str, Any]:
        user_roles = current_user.get("roles", [])
        
        if not any(role in user_roles for role in required_roles):
            raise HTTPException(
                status_code=403,
                detail="Insufficient permissions"
            )
        
        return current_user
    
    return role_checker


def require_permission(required_permissions: list[str]):
    """Decorator to require specific permissions.
    
    Args:
        required_permissions: List of required permissions
        
    Returns:
        Dependency function
    """
    async def permission_checker(
        current_user: Dict[str, Any] = Security(get_current_user)
    ) -> Dict[str, Any]:
        user_permissions = current_user.get("permissions", [])
        
        if not all(perm in user_permissions for perm in required_permissions):
            raise HTTPException(
                status_code=403,
                detail="Insufficient permissions"
            )
        
        return current_user
    
    return permission_checker


async def get_current_user_ws(websocket, token: Optional[str] = None) -> Optional[Dict[str, Any]]:
    """Get current user for WebSocket connections.
    
    Args:
        websocket: WebSocket connection
        token: JWT token from query parameters or first message
        
    Returns:
        User information or None if authentication fails
    """
    # 暂时返回模拟用户，方便测试
    return {
        "user_id": "test_user_123",
        "email": "test@example.com",
        "username": "testuser",
        "role": "user",
        "permissions": []
    }
    
    # 原始认证逻辑（暂时禁用）
    """
    try:
        # Try to get token from query parameter first
        if token:
            payload = verify_token(token)
            user_id = payload.get("sub")
            if user_id:
                return {
                    "user_id": user_id,
                    "email": payload.get("email"),
                    "username": payload.get("username"),
                    "role": payload.get("role", "user"),
                    "permissions": payload.get("permissions", [])
                }
        
        # If no token in query, wait for first message with auth
        data = await websocket.receive_json()
        if data.get("type") == "auth" and "token" in data:
            payload = verify_token(data["token"])
            user_id = payload.get("sub")
            if user_id:
                return {
                    "user_id": user_id,
                    "email": payload.get("email"),
                    "username": payload.get("username"),
                    "role": payload.get("role", "user"),
                    "permissions": payload.get("permissions", [])
                }
                
    except Exception as e:
        logger.error(f"WebSocket authentication failed: {e}")
        
    return None
    """